//
// Created by antler on 2018/12/5.
//

#include "lprefix.h"

#include <string>

#include "lua.hpp"
#include "luaext.hpp"

#include "log.h"
#include "GlobalMacros.h"

#include "XMod.h"

static int xmod_tostring(lua_State *L) {
    lua_pushfstring(L, "class: %p", lua_topointer(L, 1));
    return 1;
}

static int xmod_setconfig(lua_State *L) {
    const char *key = luaL_checkstring(L, 1);

    int type = lua_type(L, 2);
    switch (type) {
        case LUA_TNUMBER: {
            int value = lua_tointeger(L, 2);
            XMod::getInstance()->setConfig_Int(key, value);
            break;
        }
        case LUA_TBOOLEAN: {
            int value = lua_toboolean(L, 2);
            XMod::getInstance()->setConfig_Bool(key, value ? true : false);
            break;
        }
        case LUA_TSTRING: {
            const char *value = lua_tostring(L, 2);
            XMod::getInstance()->setConfig_String(key, value);
            break;
        }
        default: {
            luaL_error(L, "key:%s, value type not support", key);
            break;
        }
    }
    return 0;
}

static int xmod_getconfig(lua_State *L) {
    const char *key = luaL_checkstring(L, 1);

    int type = lua_type(L, 2);
    switch (type) {
        case LUA_TNUMBER: {
            int value = lua_tointeger(L, 2);
            int result = XMod::getInstance()->getConfig_Int(key, value);
            lua_pushinteger(L, result);
            break;
        }
        case LUA_TBOOLEAN: {
            int value = lua_toboolean(L, 2);
            XMod::getInstance()->getConfig_Bool(key, value ? true : false);
            bool result = XMod::getInstance()->getConfig_Bool(key, value);
            lua_pushboolean(L, result ? 1 : 0);
            break;
        }
        case LUA_TSTRING: {
            const char *value = lua_tostring(L, 2);
            std::string result = XMod::getInstance()->getConfig_String(key, value);
            lua_pushstring(L, result.c_str());
            break;
        }
        default: {
            luaL_error(L, "key:%s, value type not support", key);
            break;
        }
    }
    return 1;
}

static int xmod_getPublicPath(lua_State *L) {
    const std::string &path = XMod::getInstance()->getPublicPath();
    lua_pushstring(L, path.c_str());
    return 1;
}

static int xmod_getPrivatePath(lua_State *L) {
    const std::string &path = XMod::getInstance()->getPrivatePath();
    lua_pushstring(L, path.c_str());
    return 1;
}

static int xmod_resolvePath(lua_State *L) {
    const char *path = luaL_checkstring(L, 1);
    const std::string &new_path = XMod::getInstance()->resolvePath(path);
    lua_pushstring(L, new_path.c_str());
    return 1;
}

static int xmod_setOnEventCallback(lua_State *L) {
    int event = luaL_checkint(L, 1);
    int funID = toluahelper_ref_function(L, 2);
    XMod::getInstance()->setOnEventCallback(event, funID);
    return 0;
}

static int xmod_exit(lua_State *L) {
    XMod::getInstance()->exit();
    return 0;
}

static int xmod_restart(lua_State *L) {
    XMod::getInstance()->restart();
    return 0;
}

static const luaL_Reg funcs[] = {
        {"__tostring",         xmod_tostring},
        {"setConfig",          xmod_setconfig},
        {"getConfig",          xmod_getconfig},
        {"getPublicPath",      xmod_getPublicPath},
        {"getPrivatePath",     xmod_getPrivatePath},
        {"resolvePath",        xmod_resolvePath},
        {"setOnEventCallback", xmod_setOnEventCallback},
        {"exit",               xmod_exit},
        {"restart",            xmod_restart},
        {nullptr,              nullptr}
};

static int get_PLATFORM_IOS(lua_State *L) {
    lua_pushstring(L, XMod::PLATFORM_IOS);
    return 1;
}

static int get_PLATFORM_ANDROID(lua_State *L) {
    lua_pushstring(L, XMod::PLATFORM_ANDROID);
    return 1;
}

static int get_PLATFORM(lua_State *L) {
    lua_pushstring(L, XMod::getInstance()->getPlatform());
    return 1;
}

static int get_PRODUCT_CODE(lua_State *L) {
    lua_pushinteger(L, XMod::getInstance()->getProductCode());
    return 1;
}

static int get_PRODUCT_CODE_DEV(lua_State *L) {
    lua_pushinteger(L, XMod::PRODUCT_CODE_DEV);
    return 1;
}

static int get_PRODUCT_CODE_XXZS(lua_State *L) {
    lua_pushinteger(L, XMod::PRODUCT_CODE_XXZS);
    return 1;
}

static int get_PRODUCT_CODE_IPA(lua_State *L) {
    lua_pushinteger(L, XMod::PRODUCT_CODE_IPA);
    return 1;
}

static int get_PRODUCT_CODE_KUWAN(lua_State *L) {
    lua_pushinteger(L, XMod::PRODUCT_CODE_KUWAN);
    return 1;
}

static int get_PRODUCT_CODE_SPIRIT(lua_State *L) {
    lua_pushinteger(L, XMod::PRODUCT_CODE_SPIRIT);
    return 1;
}

static int get_PRODUCT_NAME(lua_State *L) {
    lua_pushstring(L, XMod::getInstance()->getProductName());
    return 1;
}

static int get_VERSION_CODE(lua_State *L) {
    lua_pushinteger(L, XMod::getInstance()->getVersionCode());
    return 1;
}

static int get_VERSION_NAME(lua_State *L) {
    lua_pushstring(L, XMod::getInstance()->getVersionName());
    return 1;
}

static int get_EVENT_ON_USER_EXIT(lua_State *L) {
    lua_pushinteger(L, XMod::EVENT_ON_USER_EXIT);
    return 1;
}

static int get_EVENT_ON_RUNTIME_ERROR(lua_State *L) {
    lua_pushinteger(L, XMod::EVENT_ON_RUNTIME_ERROR);
    return 1;
}

static int get_SCREENCAP_POLICY_STANDARD(lua_State *L) {
    lua_pushinteger(L, XMod::SCREENCAP_POLICY_STANDARD);
    return 1;
}

static int get_SCREENCAP_POLICY_AGGRESSIVE(lua_State *L) {
    lua_pushinteger(L, XMod::SCREENCAP_POLICY_AGGRESSIVE);
    return 1;
}

static int get_SCREENCAP_POLICY(lua_State *L) {
    lua_pushstring(L, XMod::SCREENCAP_POLICY);
    return 1;
}

static int get_SCREENCAP_KEEP(lua_State *L) {
    lua_pushstring(L, XMod::SCREENCAP_KEEP);
    return 1;
}

static int get_EXPECTED_ORIENTATION(lua_State *L) {
    lua_pushstring(L, XMod::EXPECTED_ORIENTATION);
    return 1;
}

static const luaL_Reg global_funcs[] = {
        {"getEngineVersion", get_VERSION_NAME},
        {"lua_exit",         xmod_exit},
        {nullptr,            nullptr}
};

LUAMOD_API int luaopen_xmod(lua_State *L) {
    tolua_open(L);

    tolua_module(L, nullptr, 0);
    tolua_beginmodule(L, nullptr);
    {
        toluahelper_setfunc(L, global_funcs);

        tolua_usertype(L, USERTYPE_XMOD);
        tolua_cclass(L, CLASSNAME_XMOD, USERTYPE_XMOD, "", nullptr);

        tolua_beginmodule(L, CLASSNAME_XMOD);
        {
            toluahelper_setfunc(L, funcs);

            TOLUAHELPER_CLASS_CONST_VARIABLE(L, PLATFORM_IOS);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, PLATFORM_ANDROID);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, PLATFORM);

            TOLUAHELPER_CLASS_CONST_VARIABLE(L, PRODUCT_CODE);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, PRODUCT_CODE_DEV);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, PRODUCT_CODE_XXZS);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, PRODUCT_CODE_IPA);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, PRODUCT_CODE_KUWAN);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, PRODUCT_CODE_SPIRIT);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, PRODUCT_NAME);

            TOLUAHELPER_CLASS_CONST_VARIABLE(L, VERSION_CODE);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, VERSION_NAME);

            TOLUAHELPER_CLASS_CONST_VARIABLE(L, EVENT_ON_USER_EXIT);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, EVENT_ON_RUNTIME_ERROR);

            TOLUAHELPER_CLASS_CONST_VARIABLE(L, SCREENCAP_POLICY_STANDARD);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, SCREENCAP_POLICY_AGGRESSIVE);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, SCREENCAP_POLICY);

            TOLUAHELPER_CLASS_CONST_VARIABLE(L, SCREENCAP_KEEP);

            TOLUAHELPER_CLASS_CONST_VARIABLE(L, EXPECTED_ORIENTATION);
        }
        tolua_endmodule(L);
    }
    tolua_endmodule(L);
    return 0;
}